home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2005 October / PCWOCT05.iso / Software / FromTheMag / XAMPP 1.4.14 / xampp-win32-1.4.14-installer.exe / xampp / php / pear / DB / sybase.php < prev   
PHP Script  |  2004-10-01  |  26KB  |  836 lines

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2004 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.02 of the PHP license,      |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Sterling Hughes <sterling@php.net>                          |
  17. // |          Ant⌠nio Carlos VenΓncio J·nior <floripa@php.net>            |
  18. // | Maintainer: Daniel Convissor <danielc@php.net>                       |
  19. // +----------------------------------------------------------------------+
  20. //
  21. // $Id: sybase.php,v 1.52 2004/07/12 19:07:34 danielc Exp $
  22.  
  23.  
  24. // TODO
  25. //    - This driver may fail with multiple connections under the same
  26. //      user/pass/host and different databases
  27.  
  28.  
  29. require_once 'DB/common.php';
  30.  
  31. /**
  32.  * Database independent query interface definition for PHP's Sybase
  33.  * extension.
  34.  *
  35.  * @package  DB
  36.  * @version  $Id: sybase.php,v 1.52 2004/07/12 19:07:34 danielc Exp $
  37.  * @category Database
  38.  * @author   Sterling Hughes <sterling@php.net>
  39.  * @author   Ant⌠nio Carlos VenΓncio J·nior <floripa@php.net>
  40.  */
  41. class DB_sybase extends DB_common
  42. {
  43.     // {{{ properties
  44.  
  45.     var $connection;
  46.     var $phptype, $dbsyntax;
  47.     var $prepare_tokens = array();
  48.     var $prepare_types = array();
  49.     var $transaction_opcount = 0;
  50.     var $autocommit = true;
  51.  
  52.     // }}}
  53.     // {{{ constructor
  54.  
  55.     /**
  56.      * DB_sybase constructor.
  57.      *
  58.      * @access public
  59.      */
  60.     function DB_sybase()
  61.     {
  62.         $this->DB_common();
  63.         $this->phptype = 'sybase';
  64.         $this->dbsyntax = 'sybase';
  65.         $this->features = array(
  66.             'prepare' => false,
  67.             'pconnect' => true,
  68.             'transactions' => false,
  69.             'limit' => 'emulate'
  70.         );
  71.         $this->errorcode_map = array(
  72.         );
  73.     }
  74.  
  75.     // }}}
  76.     // {{{ connect()
  77.  
  78.     /**
  79.      * Connect to a database and log in as the specified user.
  80.      *
  81.      * @param $dsn the data source name (see DB::parseDSN for syntax)
  82.      * @param $persistent (optional) whether the connection should
  83.      *        be persistent
  84.      * @access public
  85.      * @return int DB_OK on success, a DB error on failure
  86.      */
  87.     function connect($dsninfo, $persistent = false)
  88.     {
  89.         if (!DB::assertExtension('sybase') &&
  90.             !DB::assertExtension('sybase_ct'))
  91.         {
  92.             return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
  93.         }
  94.  
  95.         $this->dsn = $dsninfo;
  96.  
  97.         $interface = $dsninfo['hostspec'] ? $dsninfo['hostspec'] : 'localhost';
  98.         $connect_function = $persistent ? 'sybase_pconnect' : 'sybase_connect';
  99.         $dsninfo['password'] = !empty($dsninfo['password']) ? $dsninfo['password'] : false;
  100.         $dsninfo['charset'] = isset($dsninfo['charset']) ? $dsninfo['charset'] : false;
  101.         $dsninfo['appname'] = isset($dsninfo['appname']) ? $dsninfo['appname'] : false;
  102.  
  103.         if ($interface && $dsninfo['username']) {
  104.             $conn = @$connect_function($interface, $dsninfo['username'],
  105.                                        $dsninfo['password'],
  106.                                        $dsninfo['charset'],
  107.                                        $dsninfo['appname']);
  108.         } else {
  109.             $conn = false;
  110.         }
  111.  
  112.         if (!$conn) {
  113.             return $this->raiseError(DB_ERROR_CONNECT_FAILED);
  114.         }
  115.  
  116.         if ($dsninfo['database']) {
  117.             if (!@sybase_select_db($dsninfo['database'], $conn)) {
  118.                 return $this->raiseError(DB_ERROR_NODBSELECTED, null,
  119.                                          null, null, @sybase_get_last_message());
  120.             }
  121.             $this->_db = $dsninfo['database'];
  122.         }
  123.  
  124.         $this->connection = $conn;
  125.         return DB_OK;
  126.     }
  127.  
  128.     // }}}
  129.     // {{{ disconnect()
  130.  
  131.     /**
  132.      * Log out and disconnect from the database.
  133.      *
  134.      * @access public
  135.      *
  136.      * @return bool true on success, false if not connected.
  137.      */
  138.     function disconnect()
  139.     {
  140.         $ret = @sybase_close($this->connection);
  141.         $this->connection = null;
  142.         return $ret;
  143.     }
  144.  
  145.     // }}}
  146.     // {{{ errorNative()
  147.  
  148.     /**
  149.      * Get the last server error messge (if any)
  150.      *
  151.      * @return string sybase last error message
  152.      */
  153.     function errorNative()
  154.     {
  155.         return @sybase_get_last_message();
  156.     }
  157.  
  158.     // }}}
  159.     // {{{ errorCode()
  160.  
  161.     /**
  162.      * Determine PEAR::DB error code from the database's text error message.
  163.      *
  164.      * @param  string  $errormsg  error message returned from the database
  165.      * @return integer  an error number from a DB error constant
  166.      */
  167.     function errorCode($errormsg)
  168.     {
  169.         static $error_regexps;
  170.         if (!isset($error_regexps)) {
  171.             $error_regexps = array(
  172.                 '/Incorrect syntax near/'
  173.                     => DB_ERROR_SYNTAX,
  174.                 '/^Unclosed quote before the character string [\"\'].*[\"\']\./'
  175.                     => DB_ERROR_SYNTAX,
  176.                 '/Implicit conversion from datatype [\"\'].+[\"\'] to [\"\'].+[\"\'] is not allowed\./'
  177.                     => DB_ERROR_INVALID_NUMBER,
  178.                 '/Cannot drop the table [\"\'].+[\"\'], because it doesn\'t exist in the system catalogs\./'
  179.                     => DB_ERROR_NOSUCHTABLE,
  180.                 '/Only the owner of object [\"\'].+[\"\'] or a user with System Administrator \(SA\) role can run this command\./'
  181.                     => DB_ERROR_ACCESS_VIOLATION,
  182.                 '/^.+ permission denied on object .+, database .+, owner .+/'
  183.                     => DB_ERROR_ACCESS_VIOLATION,
  184.                 '/^.* permission denied, database .+, owner .+/'
  185.                     => DB_ERROR_ACCESS_VIOLATION,
  186.                 '/[^.*] not found\./'
  187.                     => DB_ERROR_NOSUCHTABLE,
  188.                 '/There is already an object named/'
  189.                     => DB_ERROR_ALREADY_EXISTS,
  190.                 '/Invalid column name/'
  191.                     => DB_ERROR_NOSUCHFIELD,
  192.                 '/does not allow null values/'
  193.                     => DB_ERROR_CONSTRAINT_NOT_NULL,
  194.                 '/Command has been aborted/'
  195.                     => DB_ERROR_CONSTRAINT,
  196.             );
  197.         }
  198.  
  199.         foreach ($error_regexps as $regexp => $code) {
  200.             if (preg_match($regexp, $errormsg)) {
  201.                 return $code;
  202.             }
  203.         }
  204.         return DB_ERROR;
  205.     }
  206.  
  207.     // }}}
  208.     // {{{ sybaseRaiseError()
  209.  
  210.     /**
  211.      * Gather information about an error, then use that info to create a
  212.      * DB error object and finally return that object.
  213.      *
  214.      * @param  integer  $errno  PEAR error number (usually a DB constant) if
  215.      *                          manually raising an error
  216.      * @return object  DB error object
  217.      * @see errorNative()
  218.      * @see errorCode()
  219.      * @see DB_common::raiseError()
  220.      */
  221.     function sybaseRaiseError($errno = null)
  222.     {
  223.         $native = $this->errorNative();
  224.         if ($errno === null) {
  225.             $errno = $this->errorCode($native);
  226.         }
  227.         return $this->raiseError($errno, null, null, null, $native);
  228.     }
  229.  
  230.     // }}}
  231.     // {{{ simpleQuery()
  232.  
  233.     /**
  234.      * Send a query to Sybase and return the results as a Sybase resource
  235.      * identifier.
  236.      *
  237.      * @param the SQL query
  238.      *
  239.      * @access public
  240.      *
  241.      * @return mixed returns a valid Sybase result for successful SELECT
  242.      * queries, DB_OK for other successful queries.  A DB error is
  243.      * returned on failure.
  244.      */
  245.     function simpleQuery($query)
  246.     {
  247.         $ismanip = DB::isManip($query);
  248.         $this->last_query = $query;
  249.         if (!@sybase_select_db($this->_db, $this->connection)) {
  250.             return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED);
  251.         }
  252.         $query = $this->modifyQuery($query);
  253.         if (!$this->autocommit && $ismanip) {
  254.             if ($this->transaction_opcount == 0) {
  255.                 $result = @sybase_query('BEGIN TRANSACTION', $this->connection);
  256.                 if (!$result) {
  257.                     return $this->sybaseRaiseError();
  258.                 }
  259.             }
  260.             $this->transaction_opcount++;
  261.         }
  262.         $result = @sybase_query($query, $this->connection);
  263.         if (!$result) {
  264.             return $this->sybaseRaiseError();
  265.         }
  266.         if (is_resource($result)) {
  267.             $numrows = $this->numRows($result);
  268.             if (is_object($numrows)) {
  269.                 return $numrows;
  270.             }
  271.             $this->num_rows[(int)$result] = $numrows;
  272.             return $result;
  273.         }
  274.         // Determine which queries that should return data, and which
  275.         // should return an error code only.
  276.         return $ismanip ? DB_OK : $result;
  277.     }
  278.  
  279.     // }}}
  280.     // {{{ nextResult()
  281.  
  282.     /**
  283.      * Move the internal sybase result pointer to the next available result
  284.      *
  285.      * @param a valid sybase result resource
  286.      *
  287.      * @access public
  288.      *
  289.      * @return true if a result is available otherwise return false
  290.      */
  291.     function nextResult($result)
  292.     {
  293.         return false;
  294.     }
  295.  
  296.     // }}}
  297.     // {{{ fetchInto()
  298.  
  299.     /**
  300.      * Fetch a row and insert the data into an existing array.
  301.      *
  302.      * Formating of the array and the data therein are configurable.
  303.      * See DB_result::fetchInto() for more information.
  304.      *
  305.      * @param resource $result    query result identifier
  306.      * @param array    $arr       (reference) array where data from the row
  307.      *                            should be placed
  308.      * @param int      $fetchmode how the resulting array should be indexed
  309.      * @param int      $rownum    the row number to fetch
  310.      *
  311.      * @return mixed DB_OK on success, null when end of result set is
  312.      *               reached or on failure
  313.      *
  314.      * @see DB_result::fetchInto()
  315.      * @access private
  316.      */
  317.     function fetchInto($result, &$arr, $fetchmode, $rownum=null)
  318.     {
  319.         if ($rownum !== null) {
  320.             if (!@sybase_data_seek($result, $rownum)) {
  321.                 return null;
  322.             }
  323.         }
  324.         if ($fetchmode & DB_FETCHMODE_ASSOC) {
  325.             if (function_exists('sybase_fetch_assoc')) {
  326.                 $arr = @sybase_fetch_assoc($result);
  327.             } else {
  328.                 if ($arr = @sybase_fetch_array($result)) {
  329.                     foreach ($arr as $key => $value) {
  330.                         if (is_int($key)) {
  331.                             unset($arr[$key]);
  332.                         }
  333.                     }
  334.                 }
  335.             }
  336.             if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
  337.                 $arr = array_change_key_case($arr, CASE_LOWER);
  338.             }
  339.         } else {
  340.             $arr = @sybase_fetch_row($result);
  341.         }
  342.         if (!$arr) {
  343.             // reported not work as seems that sybase_get_last_message()
  344.             // always return a message here
  345.             //if ($errmsg = @sybase_get_last_message()) {
  346.             //    return $this->sybaseRaiseError($errmsg);
  347.             //} else {
  348.                 return null;
  349.             //}
  350.         }
  351.         if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
  352.             $this->_rtrimArrayValues($arr);
  353.         }
  354.         if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
  355.             $this->_convertNullArrayValuesToEmpty($arr);
  356.         }
  357.         return DB_OK;
  358.     }
  359.  
  360.     // }}}
  361.     // {{{ freeResult()
  362.  
  363.     /**
  364.      * Free the internal resources associated with $result.
  365.      *
  366.      * @param $result Sybase result identifier
  367.      *
  368.      * @access public
  369.      *
  370.      * @return bool true on success, false if $result is invalid
  371.      */
  372.     function freeResult($result)
  373.     {
  374.         unset($this->num_rows[(int)$result]);
  375.         return @sybase_free_result($result);
  376.     }
  377.  
  378.     // }}}
  379.     // {{{ numCols()
  380.  
  381.     /**
  382.      * Get the number of columns in a result set.
  383.      *
  384.      * @param $result Sybase result identifier
  385.      *
  386.      * @access public
  387.      *
  388.      * @return int the number of columns per row in $result
  389.      */
  390.     function numCols($result)
  391.     {
  392.         $cols = @sybase_num_fields($result);
  393.         if (!$cols) {
  394.             return $this->sybaseRaiseError();
  395.         }
  396.         return $cols;
  397.     }
  398.  
  399.     // }}}
  400.     // {{{ numRows()
  401.  
  402.     /**
  403.      * Get the number of rows in a result set.
  404.      *
  405.      * @param $result Sybase result identifier
  406.      *
  407.      * @access public
  408.      *
  409.      * @return int the number of rows in $result
  410.      */
  411.     function numRows($result)
  412.     {
  413.         $rows = @sybase_num_rows($result);
  414.         if ($rows === false) {
  415.             return $this->sybaseRaiseError();
  416.         }
  417.         return $rows;
  418.     }
  419.  
  420.     // }}}
  421.     // {{{ affectedRows()
  422.  
  423.     /**
  424.      * Gets the number of rows affected by the data manipulation
  425.      * query.  For other queries, this function returns 0.
  426.      *
  427.      * @return number of rows affected by the last query
  428.      */
  429.     function affectedRows()
  430.     {
  431.         if (DB::isManip($this->last_query)) {
  432.             $result = @sybase_affected_rows($this->connection);
  433.         } else {
  434.             $result = 0;
  435.         }
  436.         return $result;
  437.      }
  438.  
  439.     // }}}
  440.     // {{{ nextId()
  441.  
  442.     /**
  443.      * Returns the next free id in a sequence
  444.      *
  445.      * @param string  $seq_name  name of the sequence
  446.      * @param boolean $ondemand  when true, the seqence is automatically
  447.      *                           created if it does not exist
  448.      *
  449.      * @return int  the next id number in the sequence.  DB_Error if problem.
  450.      *
  451.      * @internal
  452.      * @see DB_common::nextID()
  453.      * @access public
  454.      */
  455.     function nextId($seq_name, $ondemand = true)
  456.     {
  457.         $seqname = $this->getSequenceName($seq_name);
  458.         if (!@sybase_select_db($this->_db, $this->connection)) {
  459.             return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED);
  460.         }
  461.         $repeat = 0;
  462.         do {
  463.             $this->pushErrorHandling(PEAR_ERROR_RETURN);
  464.             $result = $this->query("INSERT INTO $seqname (vapor) VALUES (0)");
  465.             $this->popErrorHandling();
  466.             if ($ondemand && DB::isError($result) &&
  467.                 ($result->getCode() == DB_ERROR || $result->getCode() == DB_ERROR_NOSUCHTABLE))
  468.             {
  469.                 $repeat = 1;
  470.                 $result = $this->createSequence($seq_name);
  471.                 if (DB::isError($result)) {
  472.                     return $this->raiseError($result);
  473.                 }
  474.             } elseif (!DB::isError($result)) {
  475.                 $result =& $this->query("SELECT @@IDENTITY FROM $seqname");
  476.                 $repeat = 0;
  477.             } else {
  478.                 $repeat = false;
  479.             }
  480.         } while ($repeat);
  481.         if (DB::isError($result)) {
  482.             return $this->raiseError($result);
  483.         }
  484.         $result = $result->fetchRow(DB_FETCHMODE_ORDERED);
  485.         return $result[0];
  486.     }
  487.  
  488.     /**
  489.      * Creates a new sequence
  490.      *
  491.      * @param string $seq_name  name of the new sequence
  492.      *
  493.      * @return int  DB_OK on success.  A DB_Error object is returned if
  494.      *              problems arise.
  495.      *
  496.      * @internal
  497.      * @see DB_common::createSequence()
  498.      * @access public
  499.      */
  500.     function createSequence($seq_name)
  501.     {
  502.         $seqname = $this->getSequenceName($seq_name);
  503.         return $this->query("CREATE TABLE $seqname ".
  504.                             '(id numeric(10,0) IDENTITY NOT NULL ,' .
  505.                             'vapor int NULL)');
  506.     }
  507.  
  508.     // }}}
  509.     // {{{ dropSequence()
  510.  
  511.     /**
  512.      * Deletes a sequence
  513.      *
  514.      * @param string $seq_name  name of the sequence to be deleted
  515.      *
  516.      * @return int  DB_OK on success.  DB_Error if problems.
  517.      *
  518.      * @internal
  519.      * @see DB_common::dropSequence()
  520.      * @access public
  521.      */
  522.     function dropSequence($seq_name)
  523.     {
  524.         $seqname = $this->getSequenceName($seq_name);
  525.         return $this->query("DROP TABLE $seqname");
  526.     }
  527.  
  528.     // }}}
  529.     // {{{ getSpecialQuery()
  530.  
  531.     /**
  532.      * Returns the query needed to get some backend info
  533.      * @param string $type What kind of info you want to retrieve
  534.      * @return string The SQL query string
  535.      */
  536.     function getSpecialQuery($type)
  537.     {
  538.         switch ($type) {
  539.             case 'tables':
  540.                 return "select name from sysobjects where type = 'U' order by name";
  541.             case 'views':
  542.                 return "select name from sysobjects where type = 'V'";
  543.             default:
  544.                 return null;
  545.         }
  546.     }
  547.  
  548.     // }}}
  549.     // {{{ autoCommit()
  550.  
  551.     /**
  552.      * Enable/disable automatic commits
  553.      */
  554.     function autoCommit($onoff = false)
  555.     {
  556.         // XXX if $this->transaction_opcount > 0, we should probably
  557.         // issue a warning here.
  558.         $this->autocommit = $onoff ? true : false;
  559.         return DB_OK;
  560.     }
  561.  
  562.     // }}}
  563.     // {{{ commit()
  564.  
  565.     /**
  566.      * Commit the current transaction.
  567.      */
  568.     function commit()
  569.     {
  570.         if ($this->transaction_opcount > 0) {
  571.             if (!@sybase_select_db($this->_db, $this->connection)) {
  572.                 return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED);
  573.             }
  574.             $result = @sybase_query('COMMIT', $this->connection);
  575.             $this->transaction_opcount = 0;
  576.             if (!$result) {
  577.                 return $this->sybaseRaiseError();
  578.             }
  579.         }
  580.         return DB_OK;
  581.     }
  582.  
  583.     // }}}
  584.     // {{{ rollback()
  585.  
  586.     /**
  587.      * Roll back (undo) the current transaction.
  588.      */
  589.     function rollback()
  590.     {
  591.         if ($this->transaction_opcount > 0) {
  592.             if (!@sybase_select_db($this->_db, $this->connection)) {
  593.                 return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED);
  594.             }
  595.             $result = @sybase_query('ROLLBACK', $this->connection);
  596.             $this->transaction_opcount = 0;
  597.             if (!$result) {
  598.                 return $this->sybaseRaiseError();
  599.             }
  600.         }
  601.         return DB_OK;
  602.     }
  603.  
  604.     // }}}
  605.     // {{{ tableInfo()
  606.  
  607.     /**
  608.      * Returns information about a table or a result set.
  609.      *
  610.      * NOTE: only supports 'table' and 'flags' if <var>$result</var>
  611.      * is a table name.
  612.      *
  613.      * @param object|string  $result  DB_result object from a query or a
  614.      *                                string containing the name of a table
  615.      * @param int            $mode    a valid tableInfo mode
  616.      * @return array  an associative array with the information requested
  617.      *                or an error object if something is wrong
  618.      * @access public
  619.      * @internal
  620.      * @since 1.6.0
  621.      * @see DB_common::tableInfo()
  622.      */
  623.     function tableInfo($result, $mode = null)
  624.     {
  625.         if (isset($result->result)) {
  626.             /*
  627.              * Probably received a result object.
  628.              * Extract the result resource identifier.
  629.              */
  630.             $id = $result->result;
  631.             $got_string = false;
  632.         } elseif (is_string($result)) {
  633.             /*
  634.              * Probably received a table name.
  635.              * Create a result resource identifier.
  636.              */
  637.             if (!@sybase_select_db($this->_db, $this->connection)) {
  638.                 return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED);
  639.             }
  640.             $id = @sybase_query("SELECT * FROM $result WHERE 1=0",
  641.                                 $this->connection);
  642.             $got_string = true;
  643.         } else {
  644.             /*
  645.              * Probably received a result resource identifier.
  646.              * Copy it.
  647.              * Deprecated.  Here for compatibility only.
  648.              */
  649.             $id = $result;
  650.             $got_string = false;
  651.         }
  652.  
  653.         if (!is_resource($id)) {
  654.             return $this->sybaseRaiseError(DB_ERROR_NEED_MORE_DATA);
  655.         }
  656.  
  657.         if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
  658.             $case_func = 'strtolower';
  659.         } else {
  660.             $case_func = 'strval';
  661.         }
  662.  
  663.         $count = @sybase_num_fields($id);
  664.  
  665.         // made this IF due to performance (one if is faster than $count if's)
  666.         if (!$mode) {
  667.  
  668.             for ($i=0; $i<$count; $i++) {
  669.                 $f = @sybase_fetch_field($id, $i);
  670.  
  671.                 // column_source is often blank
  672.                 if ($got_string) {
  673.                     $res[$i]['table'] = $case_func($result);
  674.                 } else {
  675.                     $res[$i]['table'] = $case_func($f->column_source);
  676.                 }
  677.                 $res[$i]['name']  = $case_func($f->name);
  678.                 $res[$i]['type']  = $f->type;
  679.                 $res[$i]['len']   = $f->max_length;
  680.                 if ($res[$i]['table']) {
  681.                     $res[$i]['flags'] = $this->_sybase_field_flags(
  682.                             $res[$i]['table'], $res[$i]['name']);
  683.                 } else {
  684.                     $res[$i]['flags'] = '';
  685.                 }
  686.             }
  687.  
  688.         } else {
  689.             // get full info
  690.  
  691.             $res['num_fields'] = $count;
  692.  
  693.             for ($i=0; $i<$count; $i++) {
  694.                 $f = @sybase_fetch_field($id, $i);
  695.  
  696.                 // column_source is often blank
  697.                 if ($got_string) {
  698.                     $res[$i]['table'] = $case_func($result);
  699.                 } else {
  700.                     $res[$i]['table'] = $case_func($f->column_source);
  701.                 }
  702.                 $res[$i]['name']  = $case_func($f->name);
  703.                 $res[$i]['type']  = $f->type;
  704.                 $res[$i]['len']   = $f->max_length;
  705.                 if ($res[$i]['table']) {
  706.                     $res[$i]['flags'] = $this->_sybase_field_flags(
  707.                             $res[$i]['table'], $res[$i]['name']);
  708.                 } else {
  709.                     $res[$i]['flags'] = '';
  710.                 }
  711.  
  712.                 if ($mode & DB_TABLEINFO_ORDER) {
  713.                     $res['order'][$res[$i]['name']] = $i;
  714.                 }
  715.                 if ($mode & DB_TABLEINFO_ORDERTABLE) {
  716.                     $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
  717.                 }
  718.             }
  719.         }
  720.  
  721.         // free the result only if we were called on a table
  722.         if ($got_string) {
  723.             @sybase_free_result($id);
  724.         }
  725.         return $res;
  726.     }
  727.  
  728.     // }}}
  729.     // {{{ _sybase_field_flags()
  730.  
  731.     /**
  732.      * Get the flags for a field.
  733.      *
  734.      * Currently supports:
  735.      *  + <samp>unique_key</samp>    (unique index, unique check or primary_key)
  736.      *  + <samp>multiple_key</samp>  (multi-key index)
  737.      *
  738.      * @param string  $table   table name
  739.      * @param string  $column  field name
  740.      * @return string  space delimited string of flags.  Empty string if none.
  741.      * @access private
  742.      */
  743.     function _sybase_field_flags($table, $column)
  744.     {
  745.         static $tableName = null;
  746.         static $flags = array();
  747.  
  748.         if ($table != $tableName) {
  749.             $flags = array();
  750.             $tableName = $table;
  751.  
  752.             // get unique/primary keys
  753.             $res = $this->getAll("sp_helpindex $table", DB_FETCHMODE_ASSOC);
  754.  
  755.             if (!isset($res[0]['index_description'])) {
  756.                 return '';
  757.             }
  758.  
  759.             foreach ($res as $val) {
  760.                 $keys = explode(', ', trim($val['index_keys']));
  761.  
  762.                 if (sizeof($keys) > 1) {
  763.                     foreach ($keys as $key) {
  764.                         $this->_add_flag($flags[$key], 'multiple_key');
  765.                     }
  766.                 }
  767.  
  768.                 if (strpos($val['index_description'], 'unique')) {
  769.                     foreach ($keys as $key) {
  770.                         $this->_add_flag($flags[$key], 'unique_key');
  771.                     }
  772.                 }
  773.             }
  774.  
  775.         }
  776.  
  777.         if (array_key_exists($column, $flags)) {
  778.             return(implode(' ', $flags[$column]));
  779.         }
  780.  
  781.         return '';
  782.     }
  783.  
  784.     // }}}
  785.     // {{{ _add_flag()
  786.  
  787.     /**
  788.      * Adds a string to the flags array if the flag is not yet in there
  789.      * - if there is no flag present the array is created.
  790.      *
  791.      * @param array  $array  reference of flags array to add a value to
  792.      * @param mixed  $value  value to add to the flag array
  793.      * @access private
  794.      */
  795.     function _add_flag(&$array, $value)
  796.     {
  797.         if (!is_array($array)) {
  798.             $array = array($value);
  799.         } elseif (!in_array($value, $array)) {
  800.             array_push($array, $value);
  801.         }
  802.     }
  803.  
  804.     // }}}
  805.     // {{{ quoteIdentifier()
  806.  
  807.     /**
  808.      * Quote a string so it can be safely used as a table / column name
  809.      *
  810.      * Quoting style depends on which database driver is being used.
  811.      *
  812.      * @param string $str  identifier name to be quoted
  813.      *
  814.      * @return string  quoted identifier string
  815.      *
  816.      * @since 1.6.0
  817.      * @access public
  818.      */
  819.     function quoteIdentifier($str)
  820.     {
  821.         return '[' . str_replace(']', ']]', $str) . ']';
  822.     }
  823.  
  824.     // }}}
  825.  
  826. }
  827.  
  828. /*
  829.  * Local variables:
  830.  * tab-width: 4
  831.  * c-basic-offset: 4
  832.  * End:
  833.  */
  834.  
  835. ?>
  836.